package business;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.List;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import persistence.DAOFactory;
import persistence.DAOFactoryJdbcTestImpl;
import persistence.LibraryLocation;
import persistence.PurchaserDAO;
import persistence.Subscription;
import persistence.SubscriptionDAO;
import persistence.exception.DAOException;
import persistence.util.TestConnectionProvider;
import business.validation.BusinessValidator;
import business.validation.BusinessValidatorImpl;
import business.validation.ValidationException;
import dao.SqlProcessor;

public class SubscriptionLogicTest {
	/*TODO:
	* 
	* -> create BusinessLogicImpl, create and inject DAO mock objects, define expected behaviour
	* , call business method, verify if right methods with right params called, as often as specified
	* -> additionally perform state verification: f.e. isAdmin, also with null value
	*/
	
	/** class under test*/
	SubscriptionLogic  subscriptionLogic;
	
	/** collaborators */
	SubscriptionDAO subscriptionDAOmock;
	PurchaserDAO purchaserDAOmock;
	CommonLogic commonLogicMock;
	BusinessValidator<Subscription> validatorMock;
	
	static Subscription subscription;
	static LibraryLocation location;
	static List<Subscription> subscriptionsForLocation; 
	
	@BeforeClass
	public static void initialSetUp() throws DAOException {
/*
 * 
 * commented out to allow tests without db dependency to run
 * 
 * 	
 */
		SqlProcessor sqlProcessor = new SqlProcessor(new TestConnectionProvider());
		sqlProcessor.executeSqlScript("scripts/db_schema_hsqldb.sql");
		sqlProcessor.executeSqlScript("scripts/test_data_hsqldb.sql");
		DAOFactory factory = new DAOFactoryJdbcTestImpl();
		subscription = factory.getSubscriptionDAO().findSubscription(2);
		location = factory.getLibraryLocationDAO().find(1);
		
		subscriptionsForLocation = new ArrayList<Subscription>();
		subscriptionsForLocation.add(subscription);
		
	}
	
	@Before	
	public void setUp() {
		subscriptionDAOmock = EasyMock.createMock(SubscriptionDAO.class);
		purchaserDAOmock = EasyMock.createMock(PurchaserDAO.class);		
		validatorMock = EasyMock.createMock(BusinessValidator.class);
		commonLogicMock = EasyMock.createMock(CommonLogic.class);
		
		subscriptionLogic = new SubscriptionLogicImpl();
		subscriptionLogic.setSubscriptionDAO(subscriptionDAOmock);
		subscriptionLogic.setPurchaserDAO(purchaserDAOmock);
		
		subscriptionLogic.setCommonLogic(commonLogicMock);
		subscriptionLogic.setBusinessValidator(validatorMock);
	}

	@Test
	public void testFindGivenSubscription() throws Exception {
		expect(subscriptionDAOmock.findSubscription(2)).andReturn(subscription);
		replay(subscriptionDAOmock);
		Subscription retVal = subscriptionLogic.findGivenSubscription(2);
		assertEquals(retVal, subscription);
		verify(subscriptionDAOmock);
	}
	
	@Test
	public void testGetAllCurrencies() throws Exception {
		expect(commonLogicMock.findEntriesForParam(SubscriptionLogic.CURRENCY_PARAM)).andReturn(null);
		replay(commonLogicMock);
		subscriptionLogic.getAllCurrencies();
		verify(commonLogicMock);
	}
	
	@Test
	public void testGetAllKindsOfAcquisitions() throws Exception {
		expect(commonLogicMock.findEntriesForParam(SubscriptionLogic.KIND_OF_ACQUISITION_PARAM)).andReturn(null);
		replay(commonLogicMock);
		subscriptionLogic.getAllKindsOfAcquisition();
		verify(commonLogicMock);
	}
	
	@Test
	public void testGetAllPurchasers() throws Exception {
		expect(purchaserDAOmock.findAll()).andReturn(null);
		replay(purchaserDAOmock);
		subscriptionLogic.getAllPurchasers();
		verify(purchaserDAOmock);
	}
	
	@Test
	public void testGetAllPurchasersForLibraryLocation() throws Exception {
		expect(purchaserDAOmock.findAllForLocation(location)).andReturn(null);
		replay(purchaserDAOmock);
		subscriptionLogic.getAllPurchasersForLibraryLocation(location);
		verify(purchaserDAOmock);
	}
	
	@Test
	public void testGetAllSubscriptions() throws Exception {
		expect(subscriptionDAOmock.getAllSubscriptionsAsc()).andReturn(null);
		replay(subscriptionDAOmock);
		subscriptionLogic.getAllSubscriptions();
		verify(subscriptionDAOmock);
	}
	
	@Test
	public void testGetAllSubscriptionsForLibraryLocation() throws Exception {
		expect(subscriptionDAOmock.getAllSubscriptionsForLocation(location)).andReturn(subscriptionsForLocation);
		replay(subscriptionDAOmock);
		subscriptionLogic.getAllSubscriptionsForLibraryLocation(location);
		verify(subscriptionDAOmock);
	}
	
	@Test
	public void testGetAllSubscriptionsWithTitle() throws Exception {
		expect(subscriptionDAOmock.getAllSubscriptionsByTitle("Test Title")).andReturn(null);
		replay(subscriptionDAOmock);
		subscriptionLogic.getAllSubscriptionsWithTitle("Test Title");
		verify(subscriptionDAOmock);
	}
	
	@Test
	public void testGetAllSubscriptionsWithTitleForLibraryLocation() throws Exception {
		expect(subscriptionDAOmock.getAllSubscriptionsForLocation(location)).andReturn(subscriptionsForLocation);
		replay(subscriptionDAOmock);
		List<Subscription> retVal = subscriptionLogic.getAllSubscriptionsForLibraryLocation(location);
		verify(subscriptionDAOmock);
		assertEquals(retVal, subscriptionsForLocation);
	}
	
	@Test
	public void testSaveNewSubscription() throws Exception {
		validatorMock.validate(subscription);
		expect(subscriptionDAOmock.saveSubscription(subscription)).andReturn(null);
		replay(validatorMock, subscriptionDAOmock);
		subscriptionLogic.saveNewSubscription(subscription);
		verify(validatorMock, subscriptionDAOmock);
	}
	
	//TODO: Bsp. wie man Exception werfen kann
	@Test(expected=business.validation.ValidationException.class)
	public void testSaveNewSubscriptionFails() throws Exception {

		//set illegal value
		subscription.setCostUnit(null);
		validatorMock.validate(subscription);
		EasyMock.expectLastCall().andThrow(new ValidationException(""));
		replay(validatorMock);
		subscriptionLogic.saveNewSubscription(subscription);
		verify();
		subscription.setCostUnit(null);
	}
	
	@Test
	public void testUpdateSubscription() throws Exception {
		validatorMock.validate(subscription);
		expect(subscriptionDAOmock.updateSubscription(subscription)).andReturn(null);
		replay(validatorMock, subscriptionDAOmock);
		subscriptionLogic.updateSubscription(subscription);
		verify(validatorMock, subscriptionDAOmock);
	}
	
	@Test(expected=business.validation.ValidationException.class)
	public void testUpdateSubscriptionFails() throws Exception {
		/* wont't work because ret val of validate would be used and is null: expect(validatorMock.validate(subscription));
		 * ---> use actual DAOimpl instead
		 */
		DAOFactory factory = new DAOFactoryJdbcTestImpl();
		subscriptionLogic.setSubscriptionDAO(factory.getSubscriptionDAO());
		subscriptionLogic.setBusinessValidator(new BusinessValidatorImpl<Subscription>());
		//set illegal value
		subscription.setCostUnit(null);
		subscriptionLogic.updateSubscription(subscription);
	}
}
